<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Begin Jekyll SEO tag v2.7.1 -->
<title>Set | 微光</title>
<meta name="generator" content="Jekyll v4.2.1">
<meta property="og:title" content="Set">
<meta property="og:locale" content="en_US">
<meta name="description" content="Redis Set">
<meta property="og:description" content="Redis Set">
<link rel="canonical" href="/redis/data-type/set.html">
<meta property="og:url" content="/redis/data-type/set.html">
<meta property="og:site_name" content="微光">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-01-18T01:52:04+08:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Set">
<script type="application/ld+json">
{"description":"Redis Set","url":"/redis/data-type/set.html","headline":"Set","dateModified":"2022-01-18T01:52:04+08:00","datePublished":"2022-01-18T01:52:04+08:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"/redis/data-type/set.html"},"@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/css/normalize.css">
  <link rel="stylesheet" href="/assets/css/style.css">
<link type="application/atom+xml" rel="alternate" href="/feed.xml" title="微光">
</head>
<body>
<header class="site-header">

  <div class="wrapper">
<a class="site-title" rel="author" href="/">微光</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger">
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewbox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
            </svg>
          </span>
        </label>

        <div class="trigger">
<a class="page-link" href="/about/">About</a><a class="page-link" href="/doc/main">DocMain</a><a class="page-link" href="/sites.html">Sites</a>
</div>
      </nav>
</div>
</header>
<div class="x-collections-bar">
  <a href="/">Home</a>
  
    
      <a href="/algri/index">算法</a>
    
  
    
      <a href="/java/index">Java</a>
    
  
    
  
    
  
    
      <a href="/redis/index">Redis</a>
    
  
</div>

<div class="x-content-side-layout x-container">
  <div class="x-left">
    <h3>本文目录</h3>
    <ul id="toc" class="section-nav">
<li class="toc-entry toc-h2"><a href="#redis-set">Redis Set</a></li>
<li class="toc-entry toc-h2"><a href="#%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4">相关命令</a></li>
</ul>
  </div>
  <div class="x-content">
    <h1><strong>Redis - Set</strong></h1>
    <small>2022-01-18 01:52:04 +0800</small>
    
    <article class="x-article"><h2 id="redis-set">
<a class="anchor" href="#redis-set" aria-hidden="true"><span class="octicon octicon-link"></span></a>Redis Set</h2>

<p>Redis set 是无序的字符串集合。命令 <code class="language-plaintext highlighter-rouge">SADD</code> 把新元素添加到 set 中。Set 上还有一些其他操作，比如判断一个给定的元素是否存在，在多个集合间执行交集、并集、或者差集运算，等等。</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sadd myset 1 2 3
<span class="go">(integer) 3
</span><span class="gp">&gt;</span><span class="w"> </span>smembers myset
<span class="go">1. 3
2. 1
3. 2
</span></code></pre></div></div>

<p>这里我们往 <code class="language-plaintext highlighter-rouge">myset</code> 中添加了 3 个元素，然后告诉 redis 把所有元素返回。如你所见，它们是无序的——在每次调用时 Redis 返回元素的顺序都可能是不同的，因为 set 不向用户保证元素顺序。</p>

<p>Redis 有命令来测试成员关系。比如，检查一个元素是否存在：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sismember myset 3
<span class="go">(integer) 1
</span><span class="gp">&gt;</span><span class="w"> </span>sismember myset 30
<span class="go">(integer) 0
</span></code></pre></div></div>

<p>“3” 是 set 的成员，而 ”30“ 不是。</p>

<p>Set 非常适用于表达对象之间的关系。比如我们可以用 set 轻易地实现标签功能。这个问题的一个简单的建模方式是，用一个 set 来存储所有我们想打标签的对象。这个 set 内含有与此标签相关的对象的 ID。</p>

<p>一个例子是对新闻文章打标签。如果文章的 ID 是 1000，要对它打上标签 1、2、5和77，可以用一个集合把这些标签 ID 和新闻关联起来：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sadd news:1000:tags 1 2 5 77
<span class="go">(integer) 4
</span></code></pre></div></div>

<p>我们也可以把这个关系翻转过来：把所有的新闻和一个标签关联起来：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sadd tag:1:news 1000
<span class="go">(integer) 1
</span><span class="gp">&gt;</span><span class="w"> </span>sadd tag:2:news 1000
<span class="go">(integer) 1
</span><span class="gp">&gt;</span><span class="w"> </span>sadd tag:5:news 1000
<span class="go">(integer) 1
</span><span class="gp">&gt;</span><span class="w"> </span>sadd tag:77:news 1000
<span class="go">(integer) 1
</span></code></pre></div></div>

<p>要获取给定对象的所有标签就很简单：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>smembers news:1000:tags
<span class="go">1. 5
2. 1
3. 77
4. 2
</span></code></pre></div></div>

<p>注：在这个例子中，我们假定你有另一个数据结构，比如 Redis hash，来把标签 ID 映射到标签名。</p>

<p>还有很多不那么简单的操作可以使用适当的 Redis 命令很容易地实现。比如我们想列出所有同时包含标签 1、2、10 和 27 的对象，就可以使用 <code class="language-plaintext highlighter-rouge">SINTER</code> 命令，它在不同的集合之间求交集。我们可以这样用：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sinter tag:1:news tag:2:news tag:10:news tag:27:news
<span class="go">... results here ...
</span></code></pre></div></div>

<p>除了交集，你还可以求并集、差集、随机分离一个元素，等等。</p>

<p>从集合中分离一个元素的命令叫 <code class="language-plaintext highlighter-rouge">SPOP</code>，它适用于对特定问题建模。比如，为了实现一个 web 版的扑克游戏，你可能想用一个集合来表示你的牌。假设我们使用单字符前缀来表示梅花-(C)lubs, 方块-(D)iamonds, 红桃-(H)earts, 黑桃-(S)pades：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w">  </span>sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
<span class="go">   D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
   H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
   S7 S8 S9 S10 SJ SQ SK
   (integer) 52
</span></code></pre></div></div>

<p>现在我们给每个玩家发 5 张牌。通过命令 <code class="language-plaintext highlighter-rouge">SPOP</code> 随机移除一个元素，并返回给客户端，所以它非常适用于此场景。</p>

<p>不过，如果我们直接对牌组使用此命令，那么在下一局游戏里，我们需要再次填充牌组，这可能并不理想。所以为了开始，我们先把 <code class="language-plaintext highlighter-rouge">deck</code> key 中的牌复制一份存到 <code class="language-plaintext highlighter-rouge">game:1:deck</code> key 中。</p>

<p>This is accomplished using <code class="language-plaintext highlighter-rouge">SUNIONSTORE</code>, which normally performs the union between multiple sets, and stores the result into another set. However, since the union of a single set is itself, I can copy my deck with:</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>sunionstore game:1:deck deck
<span class="go">(integer) 52
</span></code></pre></div></div>

<p>Now I’m ready to provide the first player with five cards:</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>spop game:1:deck
<span class="go">"C6"
</span><span class="gp">&gt;</span><span class="w"> </span>spop game:1:deck
<span class="go">"CQ"
</span><span class="gp">&gt;</span><span class="w"> </span>spop game:1:deck
<span class="go">"D1"
</span><span class="gp">&gt;</span><span class="w"> </span>spop game:1:deck
<span class="go">"CJ"
</span><span class="gp">&gt;</span><span class="w"> </span>spop game:1:deck
<span class="go">"SJ"
</span></code></pre></div></div>

<p>One pair of jacks, not great…</p>

<p>This is a good time to introduce the set command that provides the number of elements inside a set. This is often called the <em>cardinality</em> of a set in the context of set theory, so the Redis command is called <code class="language-plaintext highlighter-rouge">SCARD</code>.</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span><span class="w"> </span>scard game:1:deck
<span class="go">(integer) 47
</span></code></pre></div></div>

<p>The math works: 52 - 5 = 47.</p>

<p>When you need to just get random elements without removing them from the set, there is the <code class="language-plaintext highlighter-rouge">SRANDMEMBER</code> command suitable for the task. It also features the ability to return both repeating and non-repeating elements.</p>

<h2 id="相关命令">
<a class="anchor" href="#%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4" aria-hidden="true"><span class="octicon octicon-link"></span></a>相关命令</h2>

<ul>
  <li>
<code class="language-plaintext highlighter-rouge">SADD key member [member ...]</code><br>
 <small>Add one or more members to a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SCARD key</code><br>
 <small>Get the number of members in a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SDIFF key [key ...]</code><br>
 <small>Subtract multiple sets</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SDIFFSTORE destination key [key ...]</code><br>
 <small>Subtract multiple sets and store the resulting set in a key</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SINTER key [key ...]</code><br>
 <small>Intersect multiple sets</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SINTERCARD numkeys key [key ...] [LIMIT limit]</code><br>
 <small>Intersect multiple sets and return the cardinality of the result</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SINTERSTORE destination key [key ...]</code><br>
 <small>Intersect multiple sets and store the resulting set in a key</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SISMEMBER key member</code><br>
 <small>Determine if a given value is a member of a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SMEMBERS key</code><br>
 <small>Get all the members in a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SMISMEMBER key member [member ...]</code><br>
 <small>Returns the membership associated with the given elements for a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SMOVE source destination member</code><br>
 <small>Move a member from one set to another</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SPOP key [count]</code><br>
 <small>Remove and return one or multiple random members from a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SRANDMEMBER key [count]</code><br>
 <small>Get one or multiple random members from a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SREM key member [member ...]</code><br>
 <small>Remove one or more members from a set</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SSCAN key cursor [MATCH pattern] [COUNT count]</code><br>
 <small>Incrementally iterate Set elements</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SUNION key [key ...]</code><br>
 <small>Add multiple sets</small>
</li>
  <li>
<code class="language-plaintext highlighter-rouge">SUNIONSTORE destination key [key ...]</code><br>
 <small>Add multiple sets and store the resulting set in a key</small>
</li>
</ul>
</article>
  </div>
  <div class="x-right">
    <h3>Redis</h3>
    
      <div class="x-collection-section">
        <h4>开始</h4>
        
        <ol>
          
            
              <li><a href="/redis/index.html">开始</a></li>
            
          
            
              <li><a href="/redis/install.html">安装</a></li>
            
          
            
              <li><a href="/redis/concept.html">相关概念预览</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>数据类型</h4>
        
        <ol>
          
            
              <li><a href="/redis/data-type/key-and-string.html">Key 和 String</a></li>
            
          
            
              <li><a href="/redis/data-type/list.html">List</a></li>
            
          
            
              <li><a href="/redis/data-type/hash.html">Hash</a></li>
            
          
            
              <li class="active"><a href="/redis/data-type/set.html">Set</a></li>
            
          
            
              <li><a href="/redis/data-type/zset.html">Sorted Set</a></li>
            
          
            
              <li><a href="/redis/data-type/bitmap.html">Bitmap</a></li>
            
          
            
              <li><a href="/redis/data-type/hyperloglog.html">Hyperloglog</a></li>
            
          
            
              <li><a href="/redis/data-type/geo.html">Geo</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>其他特性</h4>
        
        <ol>
          
            
              <li><a href="/redis/feature/pipeline.html">流水线处理</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>持久化</h4>
        
        <ol>
          
            
              <li><a href="/redis/persist/durability.html">持久化在说什么</a></li>
            
          
            
              <li><a href="/redis/persist/rdb.html">快照（Snapshotting）</a></li>
            
          
            
              <li><a href="/redis/persist/aof.html">AOF</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>运维</h4>
        
        <ol>
          
            
              <li><a href="/redis/ops/persistence.html">持久化方案</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>应用场景</h4>
        
        <ol>
          
            
              <li><a href="/redis/usecase/blogs.html">应用场景相关文章</a></li>
            
          
        </ol>
      </div>
    
  </div>
</div>
<footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <div class="footer-col-wrapper">
      <div class="footer-col">
        <p class="feed-subscribe">
          <a href="/feed.xml">
            <svg class="svg-icon orange">
              <use xlink:href="/assets/social-icons.svg#rss"></use>
            </svg><span>Subscribe</span>
          </a>
        </p>
      </div>
      <div class="footer-col">
        <p>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</p>
      </div>
    </div>

    <div class="social-links"></div>

  </div>

</footer>
</body>
</html>
